import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import {
  Repository,
  DataSource,
  SelectQueryBuilder,
  ObjectLiteral,
  In,
} from 'typeorm';
import { Limit } from '../utils/pagination';
import { ClassConstructor, plainToInstance } from 'class-transformer';

interface FindAllOptions<T> {
  where?: Partial<T> | ObjectLiteral;
  orderBy?: { [P in keyof T]?: 'ASC' | 'DESC' };
  search?: Partial<T> | ObjectLiteral;
  exclude?: string[];
}

interface FindOneOptions {
  exclude?: string[];
}

@Injectable()
export class CrudService<T extends ObjectLiteral> {
  constructor(
    protected readonly repository: Repository<T>,
    protected readonly dataSource: DataSource,
  ) {}

  async findAll(
    limit: Limit,
    options: FindAllOptions<T> = {},
    queryBuilderCallback?: (qb: SelectQueryBuilder<T>) => void,
  ): Promise<{ content: T[]; total: number }> {
    const { page = 0, psize = 10 } = limit;
    const { where, orderBy, search, exclude } = options;
    const queryBuilder = this.repository.createQueryBuilder('entity');

    // 处理 where 条件（完全匹配）
    if (where) {
      Object.entries(where).forEach(([key, value]) => {
        queryBuilder.andWhere(`entity.${key} = :${key}`, { [key]: value });
      });
    }

    // 处理 search 条件（模糊匹配）
    if (search) {
      Object.entries(search).forEach(([key, value]) => {
        if (value) {
          queryBuilder.andWhere(`entity.${key} LIKE :${key}`, {
            [key]: `%${value}%`,
          });
        }
      });
    }

    // 应用排序
    if (orderBy) {
      Object.entries(orderBy).forEach(([key, value]) => {
        queryBuilder.addOrderBy(`entity.${key}`, value);
      });
    }

    // 应用自定义查询构建器回调
    if (queryBuilderCallback) {
      queryBuilderCallback(queryBuilder);
    }

    const [entities, total] = await queryBuilder
      .take(psize)
      .skip(page * psize)
      .getManyAndCount();

    // 把实体类中包含@Exclude的属性过滤掉
    const transformedEntities = plainToInstance(
      this.repository.target as ClassConstructor<T>,
      entities,
      {
        excludeExtraneousValues: false,
      },
    );

    // 处理排除字段
    if (exclude) {
      transformedEntities.forEach((entity) => {
        exclude.forEach((key) => {
          if (entity[key]) {
            delete entity[key];
          }
        });
      });
    }

    return {
      content: transformedEntities,
      total,
    };
  }

  async findOne(
    id: number,
    options: FindOneOptions = {},
    queryBuilderCallback?: (qb: SelectQueryBuilder<T>) => void,
  ): Promise<T> {
    const queryBuilder = this.repository.createQueryBuilder('entity');
    const { exclude } = options;

    if (queryBuilderCallback) {
      queryBuilderCallback(queryBuilder);
    }

    queryBuilder.andWhere('entity.id = :id', { id });

    const data = await queryBuilder.getOne();

    if (!data) {
      throw new HttpException('数据不存在', HttpStatus.NOT_FOUND);
    }

    // 把实体类中包含@Exclude的属性过滤掉
    const transformedData = plainToInstance(
      this.repository.target as ClassConstructor<T>,
      data,
      {
        excludeExtraneousValues: false,
      },
    );

    // 处理排除字段
    if (exclude) {
      exclude.forEach((key) => {
        if (transformedData[key]) {
          delete transformedData[key];
        }
      });
    }

    return transformedData;
  }

  create(createDto: any): Promise<T[]> {
    const entity = this.repository.create(createDto);
    return this.repository.save(entity);
  }

  async update(id: number, updateDto: any): Promise<T> {
    if (Object.keys(updateDto).length === 0) {
      throw new HttpException('没有更新内容', HttpStatus.BAD_REQUEST);
    }
    await this.repository.update(id, updateDto);
    return this.findOne(id);
  }

  // 软删除 推荐
  async remove(id: number): Promise<boolean> {
    const data = await this.repository.findOneBy({ id } as any);
    if (!data) {
      throw new HttpException('数据不存在', HttpStatus.NOT_FOUND);
    }
    const result = await this.repository.softDelete(id);
    return result.affected > 0;
  }

  // 软删除恢复
  async restore(id: number): Promise<boolean> {
    const result = await this.repository.restore(id);
    return result.affected > 0;
  }

  // 硬删除 慎用
  async forceDelete(id: number): Promise<boolean> {
    const data = await this.repository.findOneBy({ id } as any);
    if (!data) {
      throw new HttpException('数据不存在', HttpStatus.NOT_FOUND);
    }
    const result = await this.repository.delete(id);
    return result.affected > 0;
  }

  // 批量创建
  async bulkCreate(createDtos: any[]): Promise<T[]> {
    const entities = this.repository.create(createDtos);
    return this.repository.save(entities);
  }

  // 批量更新
  async bulkUpdate(ids: number[], updateDto: any): Promise<boolean> {
    const result = await this.repository.update(
      { id: In(ids) } as any,
      updateDto,
    );
    return result.affected > 0;
  }

  // 批量删除
  async bulkRemove(ids: number[]): Promise<boolean> {
    const result = await this.repository.softDelete({ id: In(ids) } as any);
    return result.affected > 0;
  }
}
